home *** CD-ROM | disk | FTP | other *** search
/ PC User 2003 January / Disc 1 / PCU0103CD1.iso / entertn / demos / files / aomtrial.exe / AOM / AI / SCN31P4.XS < prev    next >
Encoding:
Text File  |  2002-09-03  |  21.8 KB  |  610 lines

  1. //==============================================================================
  2. // Scn31p4: AI Scenario Script for scenario 31 player 4
  3. //==============================================================================
  4. /*
  5.    AI owner:  Dave Leary
  6.    Scenario owner: Joe "The Golem" Gillum
  7.  
  8.    Overview: AI to handle the above-ground player.  This is a basic AI that
  9.     builds up and hassles the player.  If left alone, he can become a big problem,
  10.     but in general is not much of a threat (P2 is the big problem in this scenario).
  11.     This is one of the few SPC AIs that doesn't cheat, except to get some free favor
  12.     at the start, and to already have some buildings pre-built (houses, etc.)
  13.  
  14.                                   *** DIFFICULTY LEVEL NOTES ***
  15.  
  16.    Easy level - HP starts in Age 3. Enemy attack groups smaller, and do not include
  17.     ulfsarks or the mountain giant.
  18.  
  19.    Moderate level - Enemy attack groups are smaller.
  20.  
  21.    Difficult - Base level.
  22.  
  23.    Nightmare - Lots more cav and an extra mountain giant on the attack.  Three
  24.     starting towers around base.
  25. */
  26. //==============================================================================
  27.  
  28.  
  29. // Variable for main base.
  30. int gMainBaseID=-1;
  31.  
  32. //==============================================================================
  33. // Set Town Location
  34. //==============================================================================
  35. void setTownLocation(void)
  36. {
  37.    //Look for the "Town Location" marker.
  38.    kbSetTownLocation(kbGetBlockPosition("3101"));
  39. }
  40.  
  41. //==============================================================================
  42. // miscStartup
  43. //==============================================================================
  44. void miscStartup(void)
  45. {
  46.     // Difficulty Level check.
  47.     int difflevel=-1;        
  48.     difflevel=aiGetWorldDifficulty();
  49.  
  50.    //Startup message(s).
  51.    aiEcho("");
  52.    aiEcho("");
  53.    aiEcho("Scn31P4 AI Start, filename='"+cFilename+"'.");
  54.     aiEcho("Difficulty Level="+difflevel+".");
  55.    //Spit out the map size.
  56.    aiEcho("  Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+").");
  57.    //Cheat like a bastard.  Once only, though.
  58.    kbLookAtAllUnitsOnMap();
  59.    //Calculate some areas.
  60.    kbAreaCalculate(1200.0);
  61.    //Set our town location.
  62.    setTownLocation();
  63.     //Reset random seed
  64.     aiRandSetSeed();
  65.  
  66.     //Set the base location.
  67.     gMainBaseID=kbBaseGetMainID(cMyID);
  68.  
  69.     //Workarounds for crazy Ruediger bugs.
  70.     kbTechTreeAddMinorGodPref( cTechAge2Heimdall );
  71.     kbTechTreeAddMinorGodPref( cTechAge3Njord );
  72. }
  73.  
  74. //==============================================================================
  75. //==============================================================================
  76. // Attack stuff.
  77. //==============================================================================
  78. //==============================================================================
  79. //Shared variables.
  80. int numberAttacks=0;
  81. int attackPlayerID=-1;
  82.  
  83. //TODO: Decide how to rep attack group size.
  84. int attackMinimumGroupSize=3;
  85. int attackMaximumGroupSize=5;
  86.  
  87. //Attack 1 vars.
  88. int attackPlan1ID=-1;
  89.  
  90. //Attack 2 vars.
  91. int attackPlan2ID=-1;
  92.  
  93. // Route and path vars
  94. int attackRoute1ID=-1;
  95. int attackPath1ID=-1;
  96. int attackRoute2ID=-1;
  97. int attackPath2ID=-1;
  98.  
  99. // Saved plan IDs
  100. int maintainPlan1ID=-1;
  101. int maintainPlan2ID=-1;
  102. int maintainPlan3ID=-1;
  103. int maintainPlan4ID=-1;
  104. int exploreID=-1;
  105.  
  106. // Unit types
  107. int attackerUnitTypeID1=cUnitTypeVillagerNorse;
  108. int attackerUnitTypeID2=cUnitTypeUlfsark;
  109. int attackerUnitTypeID3=cUnitTypeRaidingCavalry;
  110. int attackerUnitTypeID4=cUnitTypeMountainGiant;
  111.  
  112. // Initial gather percentages
  113. float totalFoodGathererPercentage  = 0.8;
  114. float totalWoodGathererPercentage  = 0.2;
  115. float totalGoldGathererPercentage  = 0.0;
  116. float totalFavorGathererPercentage = 0.0;
  117.  
  118.  
  119. //==============================================================================
  120. // initEcon
  121. //
  122. // Set Up the initial Econonomy.
  123. //==============================================================================
  124. void initEcon()
  125. {
  126.    aiEcho("Economy Init.");
  127.  
  128.     /* Don't need this for what we're doing here.
  129.    // Set our update resource handler.
  130.    aiSetUpdateResourceEventHandler("updateResourceHandler");
  131.     */
  132.  
  133.    //-- Setup AI Cost weights.
  134.    kbSetAICostWeight(cResourceFood, 1.5);
  135.    kbSetAICostWeight(cResourceWood, 1.0);
  136.    kbSetAICostWeight(cResourceGold, 1.5);
  137.    kbSetAICostWeight(cResourceFavor, 10.0);
  138.  
  139.    //-- Dont auto gather favor
  140.    //totalFavorGathererPercentage = 0;
  141.  
  142.    //-- Set initial gatherer percentages.
  143.    aiSetResourceGathererPercentage(cResourceFood, totalFoodGathererPercentage, false, cRGPScript);
  144.    aiSetResourceGathererPercentage(cResourceWood, totalWoodGathererPercentage, false, cRGPScript);
  145.    aiSetResourceGathererPercentage(cResourceGold, totalGoldGathererPercentage, false, cRGPScript);
  146.    aiSetResourceGathererPercentage(cResourceFavor, totalFavorGathererPercentage, false, cRGPScript);
  147.    aiNormalizeResourceGathererPercentages(cRGPScript);
  148.  
  149.    //-- Set up the initial resource subtype break downs.
  150.     aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeEasy, 1, 50, 0.9, gMainBaseID);
  151.     aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeHunt, 1, 50, 0.1, gMainBaseID);
  152.     aiSetResourceBreakdown(cResourceWood, cAIResourceSubTypeEasy, 1, 50, 1.0, gMainBaseID);
  153.     aiSetResourceBreakdown(cResourceGold, cAIResourceSubTypeEasy, 1, 50, 1.0, gMainBaseID);
  154.    aiSetResourceBreakdown(cResourceFavor, cAIResourceSubTypeEasy, 1, 50, 1.0, gMainBaseID);
  155.     
  156.    //-- Set up auto-gather escrows
  157.    aiSetAutoGatherEscrowID(cRootEscrowID);
  158.    aiSetAutoFarmEscrowID(cRootEscrowID);
  159.  
  160.     //Allocate all resources to the root escrow by setting percentage of military/economy to 0.
  161.     kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0 );
  162.     kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0 );
  163.  
  164.     //-- create a herd plan to gather all herdables that we ecounter.
  165.    int herdPlanID=aiPlanCreate("HerdTest", cPlanHerd);
  166.    if (herdPlanID >= 0)
  167.    {
  168.       aiPlanAddUnitType(herdPlanID, cUnitTypeHerdable, 0, 100, 100);
  169.       aiPlanSetVariableInt(herdPlanID, cHerdPlanBuildingTypeID, 0, cUnitTypeSettlementLevel1);
  170.       aiPlanSetActive(herdPlanID);
  171.    }
  172.  
  173.     //Allocate all resources
  174.    kbEscrowAllocateCurrentResources();
  175. }
  176.  
  177. //==============================================================================
  178. // initAttack: Creates attack routes, etc.
  179. //==============================================================================
  180. void initAttack(int playerID=-1)
  181. {
  182.    //Destroy all previous attacks (if this isn't the player we're already attacking.
  183.    if (playerID != attackPlayerID)
  184.    {
  185.       //Reset the attack player ID.
  186.       attackPlayerID=-1;
  187.       //Destroy any previous attack plan.
  188.       aiPlanDestroy(attackPlan1ID);
  189.       attackPlan1ID=-1;
  190.       aiPlanDestroy(attackPlan2ID);
  191.       attackPlan2ID=-1;
  192.   
  193.       //Destroy our previous attack paths.
  194.       kbPathDestroy(attackPath1ID);
  195.       attackPath1ID=-1;
  196.       kbPathDestroy(attackPath2ID);
  197.       attackPath2ID=-1;
  198.  
  199.       //Destroy our previous attack routes.
  200.       attackRoute1ID=-1;
  201.       attackRoute2ID=-1;
  202.  
  203.       //Reset the number of attacks.
  204.       numberAttacks=0;
  205.    }
  206.  
  207.    //Save the player to attack.
  208.    attackPlayerID=playerID;
  209.  
  210.     /*
  211.  
  212.    vector gatherPoint=kbGetBlockPosition("3102");
  213.        
  214.     //Setup attack path 1 - go left
  215.    attackPath1ID=kbPathCreate("Attack Path 1");
  216.    kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3990"));
  217.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3991"));
  218.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3992"));
  219.    //Create attack route 1.
  220.    attackRoute1ID=kbCreateAttackRouteWithPath("Attack Route 1", gatherPoint, kbGetBlockPosition("3995"));
  221.    
  222.     if (attackRoute1ID >= 0)
  223.       kbAttackRouteAddPath(attackRoute1ID, attackPath1ID);
  224.  
  225.    //Setup attack path 2 - go right
  226.    attackPath2ID=kbPathCreate("Attack Path 2");
  227.    kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3990"));
  228.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3991"));
  229.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3993"));
  230.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3994"));
  231.    //Create attack route 2.
  232.    attackRoute2ID=kbCreateAttackRouteWithPath("Attack Route 2", gatherPoint, kbGetBlockPosition("3995"));
  233.    
  234.     if (attackRoute2ID >= 0)
  235.       kbAttackRouteAddPath(attackRoute2ID, attackPath2ID);
  236.     */
  237. }
  238.  
  239. //==============================================================================
  240. // setupAttack
  241. //==============================================================================
  242. bool setupAttack(int playerID=-1)
  243. {
  244.     // Difficulty Level check.
  245.     int difflevel=-1;        
  246.     difflevel=aiGetWorldDifficulty();
  247.    
  248.     //Info.
  249.     aiEcho("Attacking Player "+playerID+".");
  250.  
  251.    //If the player to attack doesn't match, init the attack.
  252.    if (attackPlayerID != playerID)
  253.    {
  254.       initAttack(playerID);
  255.       if (attackPlayerID < 0)
  256.          return(false);
  257.    }
  258.  
  259.    //Create an attack plan.
  260.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  261.    if (newAttackPlanID < 0)
  262.       return(false);
  263.  
  264.    //Target player (required).  This must work.
  265.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  266.       return(false);
  267.  
  268.    //Gather point.
  269.     vector gatherPoint=kbGetBlockPosition("3127");
  270.  
  271.     //Set the target type.  This must work.
  272.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false)
  273.       return(false);
  274.  
  275.    //Unit types to attack.
  276.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  277.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  278.  
  279.    //Attack route.
  280.     /*
  281.    if (randomPath == 0)
  282.     {
  283.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID);
  284.     }
  285.    else
  286.     {
  287.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute2ID);
  288.     }
  289.     */
  290.  
  291.    //Set the gather point and gather point distance.
  292.    aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint);
  293.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 40.0);
  294.  
  295.    //Set up the attack route usage pattern.
  296.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  297.    
  298.     //Add the unit types to the plan - cav... 
  299.     if ( difflevel == 3 )
  300.     {
  301.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 4, 4, 12);
  302.     }
  303.     else if ( difflevel > 1 )
  304.     {
  305.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 4, 4, 8);
  306.     }
  307.     else
  308.     {
  309.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 2, 2, 4);
  310.     }
  311.  
  312.     //...and ulfsarks, except on easy.
  313.     if ( difflevel > 1 )
  314.     {
  315.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, 0, 2, 6);
  316.     }
  317.     else if ( difflevel == 1 )
  318.     {
  319.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, 0, 2, 4);
  320.     }
  321.  
  322.     // ...and a single mountain giant, if available (none on easy, two on nightmare).
  323.     if ( difflevel == 3 )
  324.     {
  325.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 2, 2);
  326.     }
  327.     else if ( difflevel > 0 )
  328.     {
  329.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 1, 1);
  330.     }
  331.     
  332.    //Set the initial position.
  333.    aiPlanSetInitialPosition(newAttackPlanID, gatherPoint);
  334.    //Plan requires all need units to work (can be false).
  335.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  336.    //Activate the plan.
  337.    aiPlanSetActive(newAttackPlanID);
  338.  
  339.    //Now, save the attack plan ID appropriately.
  340.    aiPlanSetOrphan(attackPlan1ID, true);
  341.    attackPlan1ID=newAttackPlanID;
  342.  
  343.    //Increment our overall number of attacks.
  344.    numberAttacks++;
  345. }
  346.  
  347. //==============================================================================
  348. // createUnitProgression
  349. //==============================================================================
  350. int createUnitProgression(int unitTypeID=-1, string name="BUG")
  351. {
  352.    int pID=aiPlanCreate(name, cPlanProgression);
  353.    
  354.     if (pID < 0)
  355.       return(-1);
  356.  
  357.    //This is a military plan.
  358.    //aiPlanSetMilitary(pID, true);
  359.    //Set it for the building that we get our unit from.
  360.    aiPlanSetVariableInt(pID, cProgressionPlanGoalUnitID, 0, kbTechTreeGetUnitIDByTrain(unitTypeID, cMyCiv));
  361.    
  362.     //Build it in our main base using the root escrow.
  363.     aiPlanSetBaseID(pID, gMainBaseID);
  364.     aiPlanSetEscrowID(pID, cRootEscrowID);
  365.    
  366.     //Go.
  367.    aiPlanSetActive(pID);
  368.    return(pID);
  369. }
  370.  
  371. //==============================================================================
  372. // createTechProgression
  373. //==============================================================================
  374. int createTechProgression(int techID=-1, string name="BUG", int researchFromProto=-1)
  375. {
  376.    //Check for old plan.
  377.     int oldPlanID=aiPlanGetIDByTypeAndVariableType(cPlanProgression, cProgressionPlanGoalTechID, techID);
  378.    if(oldPlanID != -1)
  379.    {
  380.       aiEcho("createTechProgression: already have a plan("+oldPlanID+") for this Tech("+techID+").");
  381.       return(oldPlanID);
  382.    }
  383.    
  384.     //Create a new one.
  385.    int pID=aiPlanCreate(name, cPlanProgression);
  386.    if (pID < 0)
  387.    {
  388.       aiEcho("createTechProgression: couldn't create Progression.");
  389.       return(-1);
  390.    }
  391.    //This is a military plan.
  392.    //aiPlanSetMilitary(pID, true);
  393.    aiPlanSetVariableInt(pID, cProgressionPlanGoalTechID, 0, techID);
  394.    aiPlanSetVariableInt(pID, cProgressionPlanBuildingPref, 0, researchFromProto);
  395.    
  396.     //Build it in our main base using the root escrow.
  397.    aiPlanSetBaseID(pID, gMainBaseID);
  398.     aiPlanSetEscrowID(pID, cRootEscrowID);
  399.  
  400.    //Go.
  401.    aiPlanSetActive(pID);
  402.    aiEcho("createTechProgression: creating Tech Progression("+name+") to TechID("+techID+").");
  403.    return(pID);
  404. }
  405.  
  406. //==============================================================================
  407. // Attack Generator 1 - Send dudes now!  Or, well, soon.
  408. //==============================================================================
  409.  
  410. rule attackGenerator1
  411.    minInterval 90
  412.    inactive
  413.    group AttackRules
  414. {
  415.    //See how many "idle" attack plans we have.  Don't create any more if we have
  416.    //idle plans.
  417.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  418.  
  419.    if (numberIdleAttackPlans > 0)
  420.       return;
  421.  
  422.    //If we have enough unassigned military units, create a new attack plan.
  423.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID3);
  424.    aiEcho("There are "+numberAvailableUnits+" raiding cav available for a new attack.");
  425.    
  426.     if (numberAvailableUnits >= 4)
  427.         setupAttack(1);
  428. }
  429.  
  430. //==============================================================================
  431. // longhouseBuilt - called with an AI FUNC when he has one longhouse.
  432. //==============================================================================
  433. void longhouseBuilt( int parameter=-1 )
  434. {
  435.     // Difficulty Level check.
  436.     int difflevel=-1;        
  437.     difflevel=aiGetWorldDifficulty();
  438.  
  439.     vector gatherPointCavalry=kbGetBlockPosition("3126");
  440.  
  441.     //Maintain raiding cavalry.  Up to eight, or more on Titan.
  442.    maintainPlan3ID=aiPlanCreate("Maintain 8 "+kbGetProtoUnitName(attackerUnitTypeID3), cPlanTrain);
  443.    if (maintainPlan3ID >= 0)
  444.    {
  445.         //Must set the type of unit to train.
  446.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanUnitType, 0, attackerUnitTypeID3);
  447.       //Set the number of units to maintain in the world at one time.
  448.         if ( difflevel == 3 )
  449.         {
  450.             aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, 12);
  451.         }
  452.         else
  453.         {
  454.             aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, 8);
  455.         }
  456.       //Don't train units faster than every 20 seconds
  457.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 20);
  458.       //Set a gather point.
  459.       aiPlanSetVariableVector(maintainPlan3ID, cTrainPlanGatherPoint, 0, gatherPointCavalry);
  460.       //Activate the plan.
  461.       aiPlanSetActive(maintainPlan3ID);
  462.    }
  463.  
  464.     // Time for lots more villagers.
  465.     aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, 30);
  466.     
  467.     // Time for more ulfsarks.  Maintain ten now.
  468.     aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, 10);
  469.  
  470.     // Change percentage of who's on what.
  471.    aiSetResourceGathererPercentage(cResourceFood, 0.6, false, cRGPScript);
  472.    aiSetResourceGathererPercentage(cResourceWood, 0.1, false, cRGPScript);
  473.    aiSetResourceGathererPercentage(cResourceGold, 0.3, false, cRGPScript);
  474.     aiNormalizeResourceGathererPercentages(cRGPScript);
  475.    
  476.     // Food resource breakdown now changes to almost entirely farms.
  477.     aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeEasy, 1, 10, 0.2, gMainBaseID);
  478.     aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeHunt, 1, 10, 0.1, gMainBaseID);
  479.     aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFarm, 1, 50, 0.7, gMainBaseID);
  480.  
  481.     // Research some techs.
  482.     createTechProgression(cTechHeavyInfantry, "Research Heavy Infantry", cUnitTypeLonghouse);
  483.     createTechProgression(cTechHeavyCavalry, "Research Heavy Cavalry", cUnitTypeLonghouse);
  484.     createTechProgression(cTechIrrigation, "Research Plow", cUnitTypeOxCart);
  485.  
  486.     // Progress to Huskarls - kind of a hack, used to get him to build a hill fort.
  487.     createUnitProgression(cUnitTypeHuskarl, "Progression to Huskarls");
  488.  
  489.     // Activate attacks.  Time to beat up on the player.
  490.     xsEnableRule("attackGenerator1");
  491. }
  492.  
  493. //==============================================================================
  494. // hillFortBuilt - called with an AI FUNC when he has one hill fort.
  495. //==============================================================================
  496. void hillFortBuilt( int parameter=-1 )
  497. {
  498.     // Difficulty Level check.
  499.     int difflevel=-1;        
  500.     difflevel=aiGetWorldDifficulty();
  501.  
  502.     vector gatherPointGiants=kbGetBlockPosition("3125");
  503.  
  504.     // On Titan, cheat like a bastard.
  505.     if ( difflevel == 3 )
  506.     {
  507.         aiResourceCheat( 4, cResourceFood, 600.0 );
  508.         aiResourceCheat( 4, cResourceWood, 200.0 );
  509.         aiResourceCheat( 4, cResourceGold, 300.0 );
  510.         aiResourceCheat( 4, cResourceFavor, 50.0 );
  511.     }
  512.  
  513.     //Maintain a single mountain giant.  Adds to the fun.  :)
  514.     // Two on nightmare.
  515.    maintainPlan4ID=aiPlanCreate("Maintain 1 "+kbGetProtoUnitName(attackerUnitTypeID4), cPlanTrain);
  516.    if (maintainPlan4ID >= 0)
  517.    {
  518.         //Must set the type of unit to train.
  519.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanUnitType, 0, attackerUnitTypeID4);
  520.       //Set the number of units to maintain in the world at one time.
  521.         if ( difflevel == 3 )
  522.         {
  523.             aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToMaintain, 0, 2);
  524.         }
  525.         else
  526.         {
  527.             aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToMaintain, 0, 1);
  528.         }
  529.       //Don't train units faster than every 60 seconds
  530.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 60);
  531.       //Set a gather point.
  532.       aiPlanSetVariableVector(maintainPlan4ID, cTrainPlanGatherPoint, 0, gatherPointGiants);
  533.       //Activate the plan.
  534.       aiPlanSetActive(maintainPlan4ID);
  535.    }
  536.  
  537.     // Change percentage of who's on what.
  538.    aiSetResourceGathererPercentage(cResourceFood, 0.5, false, cRGPScript);
  539.    aiSetResourceGathererPercentage(cResourceWood, 0.1, false, cRGPScript);
  540.    aiSetResourceGathererPercentage(cResourceGold, 0.4, false, cRGPScript);
  541. }
  542.  
  543. //==============================================================================
  544. // MAIN.
  545. //==============================================================================
  546. void main(void)
  547. {
  548.     // Difficulty Level check.
  549.     int difflevel=-1;        
  550.     difflevel=aiGetWorldDifficulty();
  551.  
  552.    //Startup.
  553.    miscStartup();
  554.     initEcon();
  555.  
  556.    //Share a common gather point.
  557.    vector gatherPointVillager=kbGetBlockPosition("3101");
  558.     vector gatherPointMilitary=kbGetBlockPosition("3102");
  559.  
  560.     // Cheat up some favor.  It's tough to be Norse.
  561.     aiResourceCheat( 4, cResourceFavor, 45.0 );
  562.     
  563.    //Maintain villagers.  Fifteen should do it.
  564.    maintainPlan1ID=aiPlanCreate("Maintain 15 "+kbGetProtoUnitName(attackerUnitTypeID1), cPlanTrain);
  565.    if (maintainPlan1ID >= 0)
  566.    {
  567.         //Must set the type of unit to train.
  568.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeID1);
  569.       //You can limit the number of units that are ever trained by this plan with this call.
  570.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  571.       //Set the number of units to maintain in the world at one time.
  572.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, 12);
  573.       //Don't train units faster than every 15 seconds
  574.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 15);
  575.       //Set a gather point.
  576.       aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPointVillager);
  577.       //Activate the plan.
  578.       aiPlanSetActive(maintainPlan1ID);
  579.    }
  580.  
  581.     //Maintain ulfsarks!  Five for now.
  582.    maintainPlan2ID=aiPlanCreate("Maintain 5 "+kbGetProtoUnitName(attackerUnitTypeID2), cPlanTrain);
  583.    if (maintainPlan2ID >= 0)
  584.    {
  585.         //Must set the type of unit to train.
  586.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanUnitType, 0, attackerUnitTypeID2);
  587.       //You can limit the number of units that are ever trained by this plan with this call.
  588.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  589.       //Set the number of units to maintain in the world at one time.
  590.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, 5);
  591.       //Don't train units faster than every 20 seconds
  592.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 20);
  593.       //Set a gather point.
  594.       aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPointMilitary);
  595.       //Activate the plan.
  596.       aiPlanSetActive(maintainPlan2ID);
  597.    }
  598.  
  599.     // Explore plan
  600.    exploreID = aiPlanCreate("Explore", cPlanExplore);
  601.    if(exploreID >= 0)
  602.    {
  603.       aiPlanAddUnitType(exploreID, cUnitTypeUlfsark, 1, 1);
  604.       aiPlanSetActive(exploreID);
  605.    }
  606.  
  607.     // Prepare to create Raiding Cav.  See if it progresses smartly.
  608.     createUnitProgression(cUnitTypeRaidingCavalry, "Progression to Raiding Cav");
  609. }
  610.